package com.easyUploader.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.common.mybaits.CustomPage;
import com.common.util.StringUtil;
import com.easyUploader.entity.dao.Bucket;
import com.easyUploader.entity.dao.FileChunk;
import com.easyUploader.entity.dao.FileStorage;
import com.easyUploader.entity.dto.FileInfoDto;
import com.easyUploader.entity.vo.FileChunkVo;
import com.easyUploader.entity.dto.FileUpLoadResultDto;
import com.easyUploader.mapper.FileStorageMapper;
import com.easyUploader.property.LocalFileProperty;
import com.easyUploader.service.IBucketService;
import com.easyUploader.service.IFileChunkService;
import com.easyUploader.service.IFileStorageService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easyUploader.threadHolder.FileInfoThreadHolder;
import com.easyUploader.util.FileUtil;
import com.easyUploader.util.PathUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;
import java.util.stream.Collectors;

import static com.easyUploader.factory.FileChunkFactory.FILE_CHUNK_CONVERTER;

/**
 * <p>
 * 文件存储 服务实现类
 * </p>
 *
 * @author 大忽悠
 * @since 2022年10月29日
 */
@Service
@Slf4j
public class FileStorageServiceImpl extends ServiceImpl<FileStorageMapper, FileStorage> implements IFileStorageService {

    @Override
    public void saveLocalStorage(String resultFileName, FileChunkVo fileChunkVo) {
        String extensionName = FileUtil.getExtensionName(fileChunkVo.getFileName());
        FileStorage fileStorage = FileStorage.builder()
                .realName(fileChunkVo.getFile().getOriginalFilename())
                .name(fileChunkVo.getFileName())
                .identifier(fileChunkVo.getFileIdentifier())
                .createBy("大忽悠")
                .updateBy("大忽悠")
                .size(String.valueOf(fileChunkVo.getFile().getSize()))
                .suffix(extensionName)
                .type(FileUtil.getFileType(extensionName))
                .path(resultFileName)
                .bucketId(FileInfoThreadHolder.getBucketId())
                .build();
        save(fileStorage);
    }


    /**
     * 当前文件是否已经被完整上传
     *
     * @return
     */
    @Override
    public FileUpLoadResultDto checkFileUpLoad(String fileMd5, IFileChunkService iFileChunkService,LocalFileProperty localFileProperty) {
        FileStorage fileStorage = checkFileUpLoad(fileMd5);
        //文件已经上传
        if (fileStorage!=null) {
            String visitUrl = fileStorage.getVisitUrl(localFileProperty);
            log.info("当前分片访问的URL为: {}",visitUrl);;
            return FileUpLoadResultDto.builder().uploaded(Boolean.TRUE).visitUrl(visitUrl).build();
        }
        //返回当前文件已经上传的分片集合
        return FileUpLoadResultDto.builder()
                .uploaded(Boolean.FALSE)
                .readChunkList(iFileChunkService.list(new QueryWrapper<FileChunk>().eq("file_identifier", fileMd5)).stream().map(FileChunk::getChunkNumber).collect(Collectors.toList())).build();
    }

    @Override
    public FileStorage checkFileUpLoad(String fileMd5) {
        return getOne(new QueryWrapper<FileStorage>().eq("identifier", fileMd5));
    }

    @Override
    public List<FileInfoDto> listFileInfo(CustomPage customPage) {
        List<FileStorage> fileStorageList = CustomPage.getResult(customPage, new FileStorage(), this, null);
        return FILE_CHUNK_CONVERTER.toListFileInfoDto(fileStorageList);
    }

    @Override
    public void downLoadByBucketAndFileName(String bucket, String path, LocalFileProperty localFileProperty, IBucketService iBucketService, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        FileStorage fileStorage = getFileStorage(iBucketService, bucket, StringUtil.pathMerge(true,localFileProperty.getBaseDir(), bucket, path));
        File file = null;
        String downLoadFileName = null;
        Boolean deleteZipFile = Boolean.FALSE;
        try {
            //不存在对应的文件,或者当前name指代的是目录--暂不支持下载目录
            if (ObjectUtils.isEmpty(fileStorage)) {
                //如果发现对应的name指代的是某个目录,那么把目录打成压缩包后进行下载
                file = Bucket.zipDirIfNeeded(bucket, path, localFileProperty);
                //也不是目录--那么忽略
                if (file == null) {
                    return;
                }
                downLoadFileName = file.getName();
                deleteZipFile = Boolean.TRUE;
            } else {
                file = fileStorage.getFile();
                downLoadFileName = fileStorage.getRealName();
            }
            FileUtil.downloadFile(request, response, file, downLoadFileName, false);
        } finally {
            //删除压缩文件
            if (deleteZipFile && file != null) {
                file.delete();
            }
        }
    }

    private FileStorage getFileStorage(IBucketService iBucketService, String bucket, String path) {
        Bucket bucketOne = iBucketService.getBucketByName(bucket);
        return getOne(new QueryWrapper<FileStorage>().eq("bucket_id", bucketOne.getId()).eq("path", path));
    }

    @Override
    public Boolean deleteByBucketAndFileName(String bucket, String path, IBucketService iBucketService,LocalFileProperty localFileProperty, HttpServletRequest request, HttpServletResponse response) {
        FileStorage fileStorage = getFileStorage(iBucketService, bucket, StringUtil.pathMerge(true,localFileProperty.getBaseDir(), bucket, path));
        if (ObjectUtils.isEmpty(fileStorage)) {
            return Boolean.TRUE;
        }
        //删除文件,再删除数据库记录
        FileUtil.deleteFile(fileStorage.getPath());
        removeById(fileStorage);
        return Boolean.TRUE;
    }

    @Override
    public void visitByBucketAndFileName(LocalFileProperty localFileProperty, IBucketService iBucketService, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        String bucket = getBucketFromRequest(request);
        FileStorage fileStorage = getFileStorage(iBucketService,bucket, StringUtil.pathMerge(true,localFileProperty.getBaseDir(), bucket, getPathFromRequest(request,bucket)));
        //不存在对应的文件
        if (ObjectUtils.isEmpty(fileStorage)) {
            return;
        }
        //展示文件
        FileUtil.showFile(request, response, fileStorage.getFile(),fileStorage.getRealName(),fileStorage.getSuffix());
    }

    private String getBucketFromRequest(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        if(StringUtil.isNullOrEmpty(requestURI)){
            return "";
        }
        return URLDecoder.decode(requestURI.split("/")[2]);
    }

    private String getPathFromRequest(HttpServletRequest request, String bucket) {
           return PathUtil.modifyPathByOs(URLDecoder.decode(StringUtil.stripStrFromBegin("/visit/"+bucket,request.getRequestURI())));
    }
}
